package geektime.spring.springbucks.filter;

import com.alibaba.druid.filter.FilterChain;
import com.alibaba.druid.filter.FilterEventAdapter;
import com.alibaba.druid.proxy.jdbc.PreparedStatementProxy;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor;
import com.alibaba.druid.stat.TableStat;
import com.alibaba.druid.util.JdbcConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;

import java.sql.SQLException;
import java.util.List;

@Slf4j
public class ConnectionLogFilter extends FilterEventAdapter {

    /**
     * 可以是ORACLE、POSTGRESQL、SQLSERVER、ODPS等
     */
    final static String DB_TYPE = JdbcConstants.H2;
    public boolean preparedStatement_execute(FilterChain chain, PreparedStatementProxy statement) throws SQLException {
        try{
            List<SQLStatement> stmtList = SQLUtils.parseStatements(statement.getSql(), DB_TYPE);
            MySqlSchemaStatVisitor statVisitor =new MySqlSchemaStatVisitor();
            if(!CollectionUtils.isEmpty(stmtList)) {
                for (SQLStatement sqlStatement : stmtList) {
                    sqlStatement.accept(statVisitor);
                    for (TableStat.Condition condition : statVisitor.getConditions()) {
                        // 小于10不做处理
                        if(CollectionUtils.isEmpty(condition.getValues()) || condition.getValues().size() < 10){
                            continue;
                        }
                        throw new SQLException(String.format("参数【%s】入参个数：%s，超过 10 条限制，具体 SQL：%s",
                                condition.getColumn(), condition.getValues().size(),
                                sqlStatement));
                    }
                }
            }
        } catch (SQLException e){
            log.info("ConnectionLogFilter：执行 SQL 规则过滤器校验不通过！", e);
        } catch (Exception e){
            log.error("ConnectionLogFilter：执行 SQL 规则过滤器失败！", e);
        }
        return super.preparedStatement_execute(chain, statement);
    }
}
